/*
 * @Author: 杜颖 3263107847@qq.com
 * @Date: 2025-06-27 10:17:10
 * @LastEditors: 杜颖 3263107847@qq.com
 * @LastEditTime: 2025-06-27 16:26:54
 * @FilePath: \biji\Calculator.java
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

// 继承 JFrame 为了直接复用swing框架中窗口管理的能力
// 为了子类可以直接调用 JFrame public 的方法

// ActionListener 是java中事件处理机制的核心部分
// 为了建立计算器组件和用户操作之间的响应机制
public class Calculator extends JFrame implements ActionListener {
  // 声明界面组件
  // 上下两个容器面板 文本框区域 按钮区域
  private JPanel north, center;
  // 文本框 显示计算过程、结果或者日期时间
  private JTextField field;
  // 按钮
  private JButton[] btns;

  // 初始化窗口 - 构造器 构造方法 无参构造器
  public Calculator() {
    // 设置窗口title
    setTitle("计算器");
    // 设置窗口大小
    setSize(700, 700);
    // 设置窗口关闭时程序
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    // 设置窗口居中显示
    setLocationRelativeTo(null);
    // 初始化界面组件
    initComponent();
    // 设置窗口显示
    setVisible(true);
  }

  // 初始化界面组件
  private void initComponent() {
    // System.out.println("initComponent");
    // 创建面板容器
    // 容器面板 文本框区域
    north = new JPanel();
    // 容器面板 按钮区域
    center = new JPanel();
    // 文本框 显示计算过程、结果或者日期时间
    field = new JTextField();
    // 设置输入框大小 首选尺寸
    field.setPreferredSize(new Dimension(700, 150));
    // 禁用文字输入 禁止通过电脑键盘输入编辑
    field.setEditable(false);
    // 按钮
    // private JButton[] btns;
    // 设置输入框中文字大小
    field.setFont(new Font("SansSerif", Font.BOLD, 35));
    // 按钮文本内容
    String[] str = new String[] {
        "7", "8", "9", "+",
        "4", "5", "6", "-",
        "1", "2", "3", "×",
        "0", ".", "=", "÷",
        "C", "B", "T", "S"
    };
    // 按钮数组
    btns = new JButton[str.length];
    for (int i = 0; i < btns.length; i++) {
      btns[i] = new JButton(str[i]);
      btns[i].setFont(new Font("SansSerif", Font.BOLD, 25));
    }
    // 将组件放到窗口中
    // 设置布局管理器
    // north 顶部面板 使用 BorderLayout 边界布局
    north.setLayout(new BorderLayout());
    // center 中间面板 使用 ？ ？布局
    // center 中间面板 使用5行4列 的 网格布局
    center.setLayout(new GridLayout(5, 4));
    // 组件设置
    // field 文本框 添加到 north 顶部面板 使用 BorderLayout 居中
    north.add(field, BorderLayout.CENTER);
    // btns 按钮 添加到 center 面板 增强for循环
    for (JButton btn : btns) {
      // 通过遍历将所有按钮添加到 center 面板
      center.add(btn);
    }
    // 将 north 顶部面板 添加到窗口中
    add(north, BorderLayout.NORTH);
    // 将 center 面板 添加到窗口中
    add(center);

    // 绑定按钮的监听事件
    for (JButton btn : btns) {
      btn.addActionListener(this);
    }
  }

  // 实现接口中的抽象方法 处理事件
  // 处理按键文本
  private void setBtnText(String text) {
    // System.out.println("setBtnText:" + text);
    switch (text) {
      case "C":
        System.out.println("C");
        break;
      case "B":
        System.out.println("B");
        break;
      case "T":
        System.out.println("T");
        break;
      case "S":
        System.out.println("S");
        break;
      case "=":
        System.out.println("=");
        break;
      default:
        // 按下数字键或者运算符 要把文字放到输入框中
        // 如果之前输入框中有文字 做拼接
        String oldText = field.getText();
        field.setText(oldText + text);
        break;
    }

  }

  // 实现 ActionListener 接口中的抽象方法 处理事件
  @Override
  public void actionPerformed(ActionEvent a) {

    // 此处可以捕获到 ActionListener 监听的事件
    // System.out.println(a.getSource());
    // 获取被点击的按钮 或者按钮的文字
    Object source = a.getSource();
    if (source instanceof JButton) {
      JButton btn = (JButton) source;
      String text = btn.getText();
      // System.out.println(text);
      // 处理对应按键文字
      setBtnText(text);
    }
  }

  public static void main(String[] args) {
    // System.out.println("hello,Calculator");
    // 创建类的对象 - 线程不安全
    // new Calculator();
    // 是 Java Swing 开发中确保线程安全的核心代码
    // EDT 线程保障
    // Swing 要求所有 GUI 操作（组件创建、属性修改、事件处理）必须在 Event Dispatch Thread (EDT) 执行。这里代码通过
    // invokeLater 将 Calculator 类的实例化操作（即 GUI 初始化）提交到 EDT 队列，确保线程安全。
    // 异步执行机制
    // invokeLater 会将传入的 Runnable 任务（此处为 Calculator::new 方法引用）放入 EDT 的任务队列，由 EDT
    // 按顺序执行。这避免了直接操作 GUI 导致的线程竞争问题。
    SwingUtilities.invokeLater(Calculator::new);
  }
}